import { ref, onMounted, onUnmounted } from 'vue'
// npm install underscore
// import _ from 'underscore'
import { throttle } from 'underscore'
// import { onMounted, onUnmounted, onActivated, onDeactivated } from 'vue'

/*
  滚动监听的对象：
    1.window 窗口对象
    2.元素（overflow: auto）
  注意：监听错对象，就不会触发滚动事件
*/
/**
 * 
 * @param { ref } elRef 传入监听元素的 ref 引用
 * @returns { isReachBottom, scrollHeight, scrollTop, clientHeight }
 */
export function useScroll(elRef) {
  // 保存事件绑定的元素对象，默认为window对象
  let el = window
  // 记录页面是否滚动到底部
  const isReachBottom = ref(false)
  // 定义 ref 响应式数据对象，方便使用时导出
  const scrollTop = ref(0)
  const scrollHeight = ref(0)
  const clientHeight = ref(0)

  // 节流：在一段时间内只执行一次
  // 适用于使用次数非常频繁的函数
  const scrollListenerHandler = throttle((event) => {
    if (el === window) {
      // document.documentElement 表示 html 元素
      // Y轴的滚动距离
      scrollTop.value = document.documentElement.scrollTop
      // 页面（html元素）的总高度
      scrollHeight.value = document.documentElement.scrollHeight
      // 元素的自身高度
      clientHeight.value = document.documentElement.clientHeight
    } else {
      // document.documentElement 表示 html 元素
      // Y轴的滚动距离
      scrollTop.value = el.scrollTop
      // 页面（html元素）的总高度
      scrollHeight.value = el.scrollHeight
      // 元素的自身高度
      clientHeight.value = el.clientHeight
      // clientHeight.value = el.offsetHeight
    }

    // 页面滚动到底部时，要执行的逻辑
    // 使用 Math.ceil() 向上取整函数的原因：有些浏览器，如：Edge，会显现小数
    if (Math.ceil(scrollTop.value + clientHeight.value) >= scrollHeight.value) {
      console.log('滚动到底部了~')
      // 页面滚动到底部
      isReachBottom.value = true
    }
  }, 100)


  // 监听 window 窗口的滚动
  // 问题：如果别的页面也进行类似的监听操作，会编写重复代码
  // 解决方法：抽取封装成一个功能函数，在有需要的组件中直接调用该函数即可

  // 1.加载页面时，添加监听
  onMounted(() => {
    // 判断是否传入监听元素的ref对象
    if (elRef) el = elRef.value
    el.addEventListener('scroll', scrollListenerHandler)
  })

  // 2.离开页面时，移除监听
  onUnmounted(() => {
    el.removeEventListener('scroll', scrollListenerHandler)
  })

  // 额外补充：
  // 当组件使用 keep-alive 内置组件包裹时，还需要添加两个生命周期函数
  // 使用 keep-alive 内置组件包裹的作用：提供数据缓存功能
  // 3.当组件激活（显示）时执行
  // onActivated(() => {
  //     window.addEventListener('scroll', scrollListenerHandler)
  // })

  // 4.当离开组件时执行
  // onDeactivated(() => {
  //     window.addEventListener('scroll', scrollListenerHandler)
  // })

  // 集中返回可能用到的数据，在组件中按需导出
  return { isReachBottom, scrollHeight, scrollTop, clientHeight }
}